﻿using System.Collections;
using System.Collections.Generic;
using System.Text;
using Com.FastSearch.Esp.Search.Result;
using Com.FastSearch.SharePoint.Interfaces;

namespace Com.FastSearch.SharePoint.BL.SearchManager
{
    /// <summary>
    /// Implementation of the <see cref="IESPNavigator"/> interface, that uses
    /// navigators from the Search API.
    /// </summary>
    public class ESPNavigator : IESPNavigator
    {
        private readonly INavigator _navigator;
        private volatile IList<IESPNavigatorItem> _items;
        private readonly IList<IESPNavigatorItem> _appliedItems;

        /// <summary>
        /// Create a navigator using the given navigator from the Search API,
        /// where the list 'appliedItems' specifies which navigator items have
        /// been selected.
        /// </summary>
        /// <param name="navigator">the navigator object from the search api</param>
        /// <param name="appliedItems">the navigator items that are active</param>
        public ESPNavigator(INavigator navigator, IList<IESPNavigatorItem> appliedItems)
        {
            _navigator = navigator;
            _appliedItems = appliedItems;
        }

        #region IESPNavigator Members

        /// <inheritdoc/>
        public string Name
        {
            get { return _navigator.Name; }
        }

        /// <inheritdoc/>
        public string DisplayName
        {
            get { return _navigator.DisplayName; }
        }

        /// <inheritdoc/>
        public string Unit
        {
            get { return _navigator.Unit; }
        }

        /// <inheritdoc/>
        public int HitsUsed
        {
            get { return _navigator.HitsUsed; }
        }

        /// <inheritdoc/>
        public int ItemCount
        {
            get { return _navigator.ModifierCount(); }
        }

        /// <inheritdoc/>
        public IEnumerable<IESPNavigatorItem> NavigatorItems
        {
            get
            {
                InitializeItemLists();
                return _items;
            }
        }

        /// <inheritdoc/>
        public IEnumerable<IESPNavigatorItem> AppliedNavigatorItems
        {
            get
            {
                return _appliedItems;
            }
        }

        #endregion

        private void InitializeItemLists()
        {
            if (_items == null)
            {
                lock(this)
                {
                    if (_items == null)
                    {
                        _items = new List<IESPNavigatorItem>(ItemCount);
                        for (IEnumerator modifiers = _navigator.Modifiers().GetEnumerator(); modifiers.MoveNext(); )
                        {
                            ESPNavigatorItem item = new ESPNavigatorItem((IModifier) modifiers.Current);
                            if (!_appliedItems.Contains(item))
                            {
                                _items.Add(item);
                            }
                        }
                    }
                }
            }
        }
    }

    /// <summary>
    /// Implementation of the <see cref="IESPNavigatorItem"/> interface, that uses
    /// navigator items/modifiers from the Search API.
    /// </summary>
    public class ESPNavigatorItem : IESPNavigatorItem
    {
        private readonly string _fieldName;
        private readonly string _filterValue;
        private readonly string _displayValue;
        private readonly string _scope;
        private readonly int _resultCount;

        /// <summary>
        /// Create a navigator item using the given modifier from the Search API.
        /// </summary>
        /// <param name="modifier">the modifier object from the search api</param>
        public ESPNavigatorItem(IModifier modifier)
            : this(modifier.Attribute, modifier.Value, modifier.Name, null, modifier.Count)
        {
        }

        /// <summary>
        /// Create a navigator item using the specified parameters.
        /// </summary>
        /// <param name="fieldName">the name of the field to drill-down on</param>
        /// <param name="filterValue">the value the field should have</param>
        /// <param name="displayValue">a user-friendly representation of the field value</param>
        /// <param name="scope">the scope in which the drill-down should take place</param>
        /// <param name="resultCount">the number of documents that will be returned when the drill-down is applied</param>
        public ESPNavigatorItem(string fieldName, string filterValue, string displayValue, string scope, int resultCount)
        {
            _fieldName = fieldName;
            _filterValue = filterValue;
            _displayValue = displayValue;
            _scope = scope;
            _resultCount = resultCount;
        }

        #region IESPNavigatorItem Members

        /// <inheritdoc/>
        public string FieldName
        {
            get { return _fieldName; }
        }

        /// <inheritdoc/>
        public string FilterValue
        {
            get { return _filterValue; }
        }

        /// <inheritdoc/>
        public string DisplayValue
        {
            get { return _displayValue; }
        }

        /// <inheritdoc/>
        public int ResultCount
        {
            get { return _resultCount; }
        }

        /// <inheritdoc/>
        public string GetNavigationParam(string scope, char split)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(FieldName);
            sb.Append(split);
            sb.Append(FilterValue);
            sb.Append(split);
            sb.Append(DisplayValue);
            sb.Append(split);
            if (!string.IsNullOrEmpty(scope))
            {
                sb.Append(scope);
            }
            else if (!string.IsNullOrEmpty(_scope))
            {
                sb.Append(_scope);
            }
            return sb.ToString();
        }

        #endregion

        /// <summary>
        /// Check if the navigator item is equal to the given object. True if the
        /// object implements the interface <see cref="IESPNavigatorItem"/>, and
        /// has the same values for <see cref="FieldName"/>, <see cref="FilterValue"/>,
        /// and <see cref="DisplayValue"/>.
        /// </summary>
        /// <param name="o">the object to compare to</param>
        /// <returns>true iff this is equal to o</returns>
        public override bool Equals(object o)
        {
            if (!(o is IESPNavigatorItem))
            {
                return false;
            }
            IESPNavigatorItem item = (IESPNavigatorItem) o;
            return FieldName == item.FieldName &&
                   FilterValue == item.FilterValue &&
                   DisplayValue == item.DisplayValue;
        }

        /// <summary>
        /// Calculate a hash-code for the navigator item, consistent with <see cref="Equals"/>.
        /// </summary>
        /// <returns>a hash-code</returns>
        public override int GetHashCode()
        {
            return FieldName.GetHashCode() +
                   13 * FilterValue.GetHashCode() +
                   27 * DisplayValue.GetHashCode();
        }
    }
}
